package basic.arch.component.lock.aop.aspect.handle;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import basic.arch.component.lock.LockDetail;
import basic.arch.component.lock.LockFacade;
import basic.arch.component.lock.LockRuntimeException;
import basic.arch.component.lock.LockStatistics;
import basic.arch.component.lock.aop.annotation.Lock;
import basic.arch.component.lock.aop.aspect.key.LockKeyGenerationStrategy;
import basic.arch.component.lock.aop.aspect.key.LockSpelKeyGenerationStrategy;
import basic.arch.component.lock.config.CurrentLockSettings;
import basic.arch.component.lock.local.LockSettings;
@Service("lockAspectHandle")
public class DefaultLockAspectHandleImpl implements LockAspectHandle {

    private LockKeyGenerationStrategy keyGenerationStrategy = new LockSpelKeyGenerationStrategy();

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private LockFacade lockFacade;
    @Autowired
    private LockSettings lockSetting;
    
    
    
    @Override
    public Object handle(ProceedingJoinPoint pjp, Lock lock) throws Throwable {
        LockStatistics  lockStatistics = new LockStatistics();
        long start=System.currentTimeMillis();
        long end = 0;
        Object result = null;
        Object[] argsValue = pjp.getArgs();// 具体的参数值
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();// 方法
        Class<?>[] argsClass = method.getParameterTypes();// 参数类型
        Class<? extends Object> targetClass = pjp.getTarget().getClass();// 目标类

        String finalKey = getFinalKey(lock, argsValue, method, argsClass, targetClass);
        

        CurrentLockSettings currentLockSettings = resolveCurrentLockSettings(lock, finalKey);
        LockDetail lockDetail=null;
        
     
        try {
            lockDetail = lockFacade.acquireLock(currentLockSettings);
            if(lockDetail.getDistributionLockResult().isDistributionLockSuccess()&&lockDetail.getLocalLockResult().isLocalLockSuccess()){
                lockStatistics.setDisLockAlreadyWaitTime(lockDetail.getDistributionLockResult().getDistributionLockWaitTime());
                lockStatistics.setDisLockAlreadyWaitTime(lockDetail.getLocalLockResult().getLocalLockTime());
                lockStatistics.setDistributionAccquireLockTime(lockDetail.getDistributionLockResult().getDistributionAccquireLockTime());
                long businessStart=System.currentTimeMillis();
                result = pjp.proceed();
                end=System.currentTimeMillis();
                lockStatistics.setBusinessTime(end-businessStart);
            }else{
                throw new LockRuntimeException("key:{}获取锁失败，所以不进行业务处理,直接返回,处理失败");
            }
            
        } catch (Exception e) {
            throw e;
        } finally {
            lockFacade.unlock(lockDetail);
            
        }
        
        end=System.currentTimeMillis();
        lockStatistics.setSumTime(end-start);
        logger.info("分布式锁耗时情况：{}",lockStatistics);
        return result;
    }

    protected String getFinalKey(Lock lock, Object[] argsValue, Method method, Class<?>[] argsClass, Class<? extends Object> targetClass) throws Exception {
        String finalKey;
        if (argsClass != null && argsClass.length > 0) {
            finalKey = keyGenerationStrategy.generateKey(targetClass, lock.key(), argsValue, method, argsClass);
        } else {
            finalKey = lock.key();
        }
        StringBuilder sb = new StringBuilder();
        sb.append(lockSetting.getSystemName());
        sb.append("-");
        sb.append(lock.name());
        sb.append("-");
        sb.append(finalKey);
        finalKey = sb.toString();
        if(logger.isDebugEnabled()){
            logger.debug("最终的key:{}",finalKey);
        }
        return finalKey;
    }
    
    private CurrentLockSettings resolveCurrentLockSettings(Lock lock,String finalKey) {
        CurrentLockSettings currentLockSettings = new CurrentLockSettings();
        currentLockSettings.setCurrenLockKey(finalKey);
        currentLockSettings.setDistributionLockMaxWaitTime(lock.distributeLockMaxWaitTime());
        currentLockSettings.setLocalLockMaxWaitTime(lock.localLockMaxWaitTime());
        currentLockSettings.setTryTimes(lock.tryTimes());
        currentLockSettings.setDisstributionLockType(lock.disstributionLockType());
        return currentLockSettings;

    }

}
